using System;
using System.Collections.Generic;
using System.Diagnostics;
using BSDS.Commands.Commands;
using BSDS.Commands.Initalization;
using BSDS.Core.Infrastructure.Logging;
using BSDS.Core.Intialization;
using BSDS.Service.Commands;
using BSDS.Service.Configuration;
using BSDS.Service.Logic;
using BSDS.Service.Initialization;
using BSDS.Service.Utils;

namespace BSDS.Service
{
    public class BsdsServiceApplication
    {
        private Logger initialLogger;
        private BsdsEngine bsdsEngine;

        private FileProcessor fileProcessor;
        private SchedulingProcessor schedulingProcessor;

        public void Start()
        {
            initialLogger = null;

            try
            {
                initialLogger = new Logger("Service", new TraceSource("BSDS.Service"), new List<ILogConsumer>());
                initialLogger.Log("BSDS Service started");

                var configuration = new ConfigurationLoader().Load();

                var fileHandler = new FilesManager(configuration.InputDirectory, configuration.FilesPergingOptions);
                fileHandler.Initialize();

                bsdsEngine = new BsdsEngine();
                bsdsEngine.Initialize(new ServiceIntializationOptionsProvider());

                var logger = bsdsEngine.Services.LoggerFactory.Create("Service", new TraceSource("BSDS.Service"));
                var dispatcher = CreateDispatcher();
                
                var commandExecutor = new CommandExecutor(dispatcher, logger, configuration.CommandTemplate);

                if (configuration.AutoExecutionOptions.AutoExecute)
                {
                    SetupSchedulingProcessor(configuration, commandExecutor, logger);
                }
                else
                {
                    SetupFileProcessor(commandExecutor, fileHandler, logger, configuration);
                }
            }
            catch (Exception e)
            {
                if (initialLogger != null)
                {
                    initialLogger.Log("Error: " + e.Message);
                }

                throw;
            }
        }

        private void SetupSchedulingProcessor(BsdsServiceConfiguration configuration, CommandExecutor commandExecutor,
                                              Logger logger)
        {
            schedulingProcessor = new SchedulingProcessor(logger, commandExecutor, configuration.AutoExecutionOptions);
            schedulingProcessor.Initialize();
        }

        private void SetupFileProcessor(CommandExecutor commandExecutor, FilesManager fileHandler, Logger logger,
                                      BsdsServiceConfiguration configuration)
        {
            var fileWatcherFactory = new FileWatcherFactory(configuration.MaxFileCopyTime, logger);
            fileProcessor = new FileProcessor(bsdsEngine.Services.TempFolderManager, fileHandler, commandExecutor,
                                              logger, fileWatcherFactory,
                                              configuration.FilesPergingOptions.CleanTempAfterEachCommand);
            fileProcessor.Intialize();
        }


        private CommandDispatcher CreateDispatcher()
        {
            var dispatcher = new CommandsModule().Build(
                bsdsEngine.Services, 
                new ICommandCreatorOverride[] {new GeocodeCommandCreatorOverride(), new DownloadCommandCreatorOverride()});

            return dispatcher;
        }


        public void Stop()
        {
            if (bsdsEngine != null)
            {
                bsdsEngine.Dispose();
            }
        }
    }
}